use std::rc::Rc;

use cgmath::Vector4;
use tetris_core::math::Rect;
use wgpu::include_wgsl;

use super::{
    board::{v2dcq, Vertex2DC},
    framework::{mesh::MeshInstance, shader::Shader, Context},
};

pub struct RectBatch {
    pipeline: Rc<wgpu::RenderPipeline>,
    mesh: MeshInstance<Vertex2DC>,
}

impl RectBatch {
    pub fn new(ctx: &Context, global_layout: &wgpu::BindGroupLayout) -> Self {
        let layout = ctx.create_pipeline_layout(&[global_layout]);
        let shader =
            Shader::with_vertex_screen::<Vertex2DC>(ctx, include_wgsl!("../../shaders/batch.wgsl"));

        let pipeline = ctx.create_simple_render_pipeline(
            &layout,
            &shader,
            wgpu::PrimitiveState {
                front_face: wgpu::FrontFace::Cw,
                cull_mode: Some(wgpu::Face::Back),
                ..Default::default()
            },
        );

        Self::with_pipeline(ctx, Rc::new(pipeline))
    }

    pub fn with_pipeline(ctx: &Context, pipeline: Rc<wgpu::RenderPipeline>) -> Self {
        let mesh = MeshInstance::new(ctx);

        Self { pipeline, mesh }
    }

    pub fn add_rect(&mut self, rect: Rect, color: Vector4<f32>) {
        self.mesh.add_quad(v2dcq(
            [
                rect.left_bottom(),
                rect.left_top(),
                rect.right_top(),
                rect.right_bottom(),
            ],
            color,
        ))
    }

    pub fn clear(&mut self) {
        self.mesh.clear();
    }

    pub fn prepare(&mut self, ctx: &Context) {
        self.mesh.prepare(ctx);
    }

    pub fn render<'p>(&'p mut self, pass: &mut wgpu::RenderPass<'p>) {
        pass.set_pipeline(&self.pipeline);
        self.mesh.render(pass);
    }
}
